package com.ordertracker.client;

import java.io.StringWriter;

import javax.ws.rs.core.MultivaluedMap;
import javax.xml.bind.JAXBException;

import com.ordertracker.protocol.CommandMessage;
import com.ordertracker.protocol.RequestAuthorization;
import com.ordertracker.protocol.ResponseAuthorization;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.json.JSONConfiguration;
import com.sun.jersey.api.json.JSONJAXBContext;
import com.sun.jersey.api.json.JSONMarshaller;
import com.sun.jersey.oauth.client.OAuthClientFilter;
import com.sun.jersey.oauth.signature.OAuthParameters;
import com.sun.jersey.oauth.signature.OAuthSecrets;

/**
 * Description of class. Created 1/18/13 5:00 PM
 * 
 * @author andrey.rodin@playtech.com
 */

public class RestClient {

    private static final String APPLICATION_JSON = "application/json";

    private JSONMarshaller jsonMarshaller;
    private JSONJAXBContext context;
    private ClientConfig clientConfig;
    private Client client;
    private WebResource.Builder builder;
    private WebResource resource;
    private RequestAuthorization authorization;
    private ClientSession clientSession;
    private String sessionToken;
    private String sessionKey;
    private OAuthParameters oAuthParameters;
    private OAuthSecrets oAuthSecrets;
    private OAuthClientFilter oAuthClientFilter;

    public RestClient(JSONJAXBContext context, JSONMarshaller jsonMarshaller, RequestAuthorization authorization) {
        this.jsonMarshaller = jsonMarshaller;
        this.context = context;
        this.authorization = authorization;
        clientConfig = new DefaultClientConfig();
        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
        client = Client.create(clientConfig);
        oAuthParameters = new OAuthParameters();
        oAuthSecrets = new OAuthSecrets();
    }

    public WebResource createWebResource(String webResource) {
        resource = client.resource(webResource);
        builder = resource.type(APPLICATION_JSON);
        return resource;
    }

    public ClientResponse sendPost(Object obj, Class type) {
        CommandMessage message = creatrMessage(obj, type);
        addFilter();
        return resource.type(APPLICATION_JSON).post(ClientResponse.class, message);
    }

    public ClientResponse sendGet() {
        addFilter();
        return resource.type(APPLICATION_JSON).get(ClientResponse.class);
    }

    public ClientResponse sendGetWithParam(MultivaluedMap<String, String> params) {
        addFilter();
        return resource.queryParams(params).type(APPLICATION_JSON).get(ClientResponse.class);
    }

    public ResponseAuthorization sendAuthorization() {
        ClientResponse clientResponse = builder.type(APPLICATION_JSON).post(ClientResponse.class, authorization);
        System.out.println(clientResponse.getClientResponseStatus().name());
        ResponseAuthorization respAuthorization = clientResponse.getEntity(ResponseAuthorization.class);
        clientSession = respAuthorization.getClientSession();
        sessionToken = clientSession.getSessionToken();
        sessionKey = clientSession.getSessionKey();
        oAuthParameters.consumerKey(sessionKey).signatureMethod("HMAC-SHA1").token(sessionToken);
        oAuthSecrets.consumerSecret(new String(respAuthorization.getClientSession().getSessionSecret()));
        oAuthClientFilter = new OAuthClientFilter(client.getProviders(), oAuthParameters, oAuthSecrets);
        resource.addFilter(oAuthClientFilter);
        return respAuthorization;
    }

    public ResponseAuthorization sendAuthorization(RequestAuthorization requestAuthorization) {
        authorization = requestAuthorization;
        ClientResponse clientResponse = builder.post(ClientResponse.class, requestAuthorization);
        ResponseAuthorization respAuthorization = clientResponse.getEntity(ResponseAuthorization.class);
        clientSession = respAuthorization.getClientSession();
        sessionToken = clientSession.getSessionToken();
        sessionKey = clientSession.getSessionKey();
        oAuthParameters.consumerKey(sessionKey).signatureMethod("HMAC-SHA1").token(sessionToken);
        oAuthSecrets.consumerSecret(new String(respAuthorization.getClientSession().getSessionSecret()));
        oAuthClientFilter = new OAuthClientFilter(client.getProviders(), oAuthParameters, oAuthSecrets);
        resource.addFilter(oAuthClientFilter);
        return respAuthorization;
    }

    public void logout(String url) {
        createWebResource(url);
        addFilter();
        ClientResponse clientResponse = resource.type(APPLICATION_JSON).post(ClientResponse.class, clientSession);
        if (clientResponse.getStatus() != 301) {
            throw new ClientHandlerException("Not successfully !");
        }
        clearData();
    }

    private void clearData() {
        clientSession = null;
        authorization = null;
        sessionToken = null;
        sessionKey =  null;
        oAuthParameters = null;
        oAuthSecrets = null;
        oAuthClientFilter = null;
        jsonMarshaller = null;
        context = null;
        clientConfig = null;
        client = null;
        builder = null;
        resource = null;
    }

    private CommandMessage creatrMessage(Object obj, Class type) {
        StringWriter sw = new StringWriter();
        try {
            jsonMarshaller.marshallToJSON(obj, sw);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        return new CommandMessage(sw.toString(), type);
    }

    public JSONMarshaller getJsonMarshaller() {
        return jsonMarshaller;
    }

    public JSONJAXBContext getContext() {
        return context;
    }

    public ClientConfig getClientConfig() {
        return clientConfig;
    }

    public void setClientConfig(ClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }

    public WebResource getResource() {
        return resource;
    }

    public void setResource(WebResource resource) {
        this.resource = resource;
    }

    private void addFilter() {
        if (!resource.isFilterPreset(oAuthClientFilter)) {
            resource.addFilter(oAuthClientFilter);
        }
    }
}
